home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_12_02 / smith / ebaz.c < prev    next >
C/C++ Source or Header  |  1993-12-29  |  5KB  |  168 lines

  1. /* EBAZ.Cz
  2.  * Contributed to Public Domain 9/93
  3.  * by Thad Smith, Boulder Co.
  4.  */
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "baz.h"
  8. #include "bazcom.h"
  9. #include "crc16.h"
  10.  
  11. static unsigned int crc;/* input CRC */
  12. static int  width;      /* # output chars/line  */
  13. static int  col;        /* current column       */
  14. static int  ninb;       /* # bytes in inbuf     */
  15. static unsigned char inbuf[BINB_LEN * 2];
  16. static char outbuf[ENCB_LEN * 2];
  17. static int  (*outfunc) (const char *out, size_t len);
  18.  
  19. #define BASESQ  (unsigned long)(BASE*BASE)
  20. #define MAKE_PRINT(c)  (char)((c)+FIRST_CODE)
  21. #define CV2ASCII(p,v)  ((p)[0]=MAKE_PRINT((v)/BASE), \
  22.                         (p)[1]=MAKE_PRINT((v)%BASE))
  23.  
  24. static int  putn (const char *out, int n);
  25.  
  26. /* Initialize the BAZ911 encoder. */
  27. int ebaz_init (
  28.    int p_width,            /* width of output lines */
  29.    outf_t *p_outfunc
  30. ) {
  31.    initcrctab ();
  32.    crc = CRC_INIT_VALUE;
  33.    ninb = 0;
  34.    col = 0;
  35.    outfunc = p_outfunc;
  36.    width = p_width;
  37.    return 0;
  38. }
  39.  
  40. /* Encode the next block of data. */
  41. int ebaz_data (
  42.    const unsigned char *data,
  43.    size_t len           /* length of data or 0=end  */
  44. ) {
  45.    int         s;       /* output return status */
  46.  
  47.    if (len) {
  48.       unsigned int cl;  /* # bytes needed for block */
  49.       while (len > MAX_ENDBLK_DB - ninb) {
  50.          if (ninb) {
  51.             if (ninb < BINB_LEN) {
  52.                cl = BINB_LEN - ninb;
  53.                memcpy (inbuf + ninb, data, cl);
  54.                len -= cl;
  55.                data += cl;
  56.                ninb = BINB_LEN;
  57.             }
  58.  
  59.             /* convert block in inbuf */
  60.             crc = updcrc (crc, inbuf, BINB_LEN);
  61.             encode_9_to_11 (outbuf, inbuf);
  62.             if ((s = putn (outbuf, ENCB_LEN)) != 0)
  63.                return s;
  64.  
  65.             /* Now move remainder in inbuf down */
  66.             memmove (inbuf, inbuf + BINB_LEN,
  67.                     ninb -= BINB_LEN);
  68.          } else {
  69.             /* Encode full blocks from input buffer */
  70.             for (; len > MAX_ENDBLK_DB;
  71.                  data += BINB_LEN, len -= BINB_LEN) {
  72.  
  73.                crc = updcrc (crc, data, BINB_LEN);
  74.                encode_9_to_11 (outbuf, data);
  75.                if ((s = putn (outbuf, ENCB_LEN)) != 0)
  76.                   return s;
  77.             }
  78.          }
  79.       }
  80.       /* Copy remainder of input to working buffer  */
  81.       memcpy (inbuf + ninb, data, len);
  82.       ninb += len;
  83.       return 0;
  84.  
  85.    } else {             /* final block of data */
  86.       /** Write endmarker with final byte count.
  87.        * Insert CRC and fill out blocks with 0xff to
  88.        * prevent change when output is truncated.   */
  89.       char        endmark[2];
  90.       endmark[0] = END_FLAG;
  91.       endmark[1] = MAKE_PRINT(ninb);
  92.       if ((s = putn (endmark, sizeof endmark)) != 0)
  93.          return s;
  94.  
  95.       crc = updcrc (crc, inbuf, ninb);
  96.       inbuf[ninb++] = (crc >> 8) & 0xff;
  97.       inbuf[ninb++] = crc & 0xff;
  98.       memset (inbuf + ninb, 0xff, BINB_LEN * 2 - ninb);
  99.       encode_9_to_11 (outbuf, inbuf);
  100.       if (ninb > BINB_LEN) {
  101.          ninb += 2;
  102.          encode_9_to_11 (outbuf + ENCB_LEN,
  103.                         inbuf + BINB_LEN);
  104.       } else if (ninb < BINB_LEN-2) ninb = BINB_LEN-2;
  105.       /* Truncate the last block to the number of
  106.        * required characters for the length.        */
  107.       if ((s = putn (outbuf, ninb + 2)) != 0)
  108.          return s;
  109.       return outfunc ("\n", 1);
  110.    }
  111. }
  112.  
  113. /* Send output to the output function, adding newline
  114.  * character every width encoded characters.        */
  115. static int
  116. putn (const char *out, int n)
  117. {
  118.    int         s;       /* output return status */
  119.  
  120.    while (width && col + n > width) {
  121.       if (width > col) {
  122.          if ((s = outfunc (out, width - col)) != 0)
  123.             return s;
  124.       }
  125.       if ((s = outfunc ("\n", 1)) != 0)
  126.          return s;
  127.       n   -= (width - col);
  128.       out += (width - col);
  129.       col  = 0;
  130.    }
  131.    col += n;
  132.    return outfunc (out, n);
  133. }
  134.  
  135. /* Encode 9 bytes into 11 printable ASCII chars.    */
  136. void encode_9_to_11 (char out[11],
  137.                      const unsigned char in[9])
  138. {
  139.    unsigned long block; /* conversion area      */
  140.    int         i;       /* input byte index     */
  141.    unsigned int qb = 0; /* prefixes             */
  142.    ldiv_t      ld;      /* quotient, remainder  */
  143.  
  144.    for (i = 1; i < 9; i += 4) {
  145.       unsigned    q;
  146.       block = ((unsigned long)
  147.                (((unsigned)in[i+0]<<8) | in[i+1])<<16)+
  148.               (((unsigned) in[i+2]<<8) | in[i+3]);
  149.  
  150.       q = (unsigned) (block >> 16) / PBMULT;
  151.       block = block- ((unsigned long)(q*PBMULT) << 16);
  152.       ld = ldiv ((long) block, (long) BASESQ);
  153.       CV2ASCII(out+i+2, (unsigned) ld.quot);
  154.       CV2ASCII(out+i+4, (unsigned) ld.rem);
  155.       qb = qb * PBASE + q;
  156.    }
  157.  
  158.    /* Now convert the remaining byte and prefixes
  159.     * from previous block conversions               */
  160.    block = ((unsigned long) qb << 8) | in[0];
  161.    ld = ldiv ((long) block, (long) BASESQ);
  162.    out[0] = MAKE_PRINT((unsigned) ld.quot);
  163.    CV2ASCII(out+1, (unsigned) ld.rem);
  164. }
  165.  
  166. /* End of file */
  167.  
  168.